library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

--
--
-- Base 4 division. Includes sign control
entity divider_signed is
	PORT (
	clk : in STD_LOGIC;
	start_division : in STD_LOGIC;
	numerator : in STD_LOGIC_VECTOR(31 downto 0);
	denominator : in STD_LOGIC_VECTOR(31 downto 0);
	is_signed : in STD_LOGIC; -- 1 for signed, 0 for unsigned
	
	quotient : out STD_LOGIC_VECTOR (31 downto 0);
	remainder : out STD_LOGIC_VECTOR (31 downto 0);
	
	div_0_flag : out STD_LOGIC;
	overflow_flag : out STD_LOGIC
	);
end divider_signed;

architecture Behavioral of divider_signed is	
	
	component div_preprocess_layer is
	PORT (
		clk : in STD_LOGIC;
		denominator : in STD_LOGIC_VECTOR(31 downto 0);
		is_signed : in STD_LOGIC;
		
		out_m_1 : out STD_LOGIC_VECTOR(34 downto 0);
		out_m_2 : out STD_LOGIC_VECTOR(34 downto 0);
		out_m_3 : out STD_LOGIC_VECTOR(34 downto 0)
		);
	end component;
	
	component div_sub_and_select is

	PORT (
		
		times1 : in STD_LOGIC_VECTOR(34 downto 0);
		times2 : in STD_LOGIC_VECTOR(34 downto 0);
		times3 : in STD_LOGIC_VECTOR(34 downto 0);
		
		feedback_in : in STD_LOGIC_VECTOR(31 downto 0);
		
		is_signed : in STD_LOGIC; 
		
		out_diff : out STD_LOGIC_VECTOR(31 downto 0);
		quotient_digit : out STD_LOGIC_VECTOR(1 downto 0)
	
	);	
	end component;

	component div_signed_base_4_latch_layer is
	PORT(
		clk : in STD_LOGIC; 
		start : in STD_LOGIC;
		
		numerator : in STD_LOGIC_VECTOR(31 downto 0);
		new_partial_remainder : in STD_LOGIC_VECTOR(31 downto 0);
		quotient_digit : in STD_LOGIC_VECTOR(1 downto 0);
		is_signed : in STD_LOGIC;
		
		output : out STD_LOGIC_VECTOR(63 downto 0)
	);
	end component;
	
	component div_remainder_handler is
	port(
	remainder : in STD_LOGIC_VECTOR(31 downto 0);
	numerator_sign : in STD_LOGIC;
	is_signed : in STD_LOGIC;
	
	final_remainder : out STD_LOGIC_VECTOR(31 downto 0)
	
	);
	end component;

	component quotient_handler is
		port(
		quotient_in : in STD_LOGIC_VECTOR(31 downto 0); -- for converting quotient
		
		is_signed : in STD_LOGIC;
		denominator_sign : in STD_LOGIC;
		numerator_sign: in STD_LOGIC;
		
		output : out STD_LOGIC_VECTOR(31 downto 0)
		
		
		);
	end component;
	
	-- preprocessed signals
	signal preprocessed1 : STD_LOGIC_VECTOR(34 downto 0);
	signal preprocessed2 : STD_LOGIC_VECTOR(34 downto 0);
	signal preprocessed3 : STD_LOGIC_VECTOR(34 downto 0);
	
	-- latch signals
	signal new_partial_remainder : STD_LOGIC_VECTOR(31 downto 0);
	signal new_quotient_digit : STD_LOGIC_VECTOR(1 downto 0);
	signal old_partial_remainder : STD_LOGIC_VECTOR(31 downto 0);
	
	signal output : STD_LOGIC_VECTOR(63 downto 0);
	
begin
	
	latch_me : div_signed_base_4_latch_layer
	PORT map(
	clk => clk,
	start => start_division,
	is_signed => is_signed,
	numerator => numerator,
	new_partial_remainder => new_partial_remainder,
	quotient_digit => new_quotient_digit,
	
	output => output
	);
	
	
	subtractor_layer : div_sub_and_select
	PORT map (
		
		times1 => preprocessed1,
		times2 => preprocessed2,
		times3 => preprocessed3,
		
		feedback_in => old_partial_remainder,
		
		is_signed => is_signed,
		
		out_diff => new_partial_remainder,
		quotient_digit => new_quotient_digit
	
	);	
	
	preprocess : div_preprocess_layer
	PORT map(
		clk => clk,
		denominator => denominator,
		is_signed => is_signed,
		
		out_m_1 => preprocessed1,
		out_m_2 => preprocessed2,
		out_m_3 => preprocessed3
		);
	
	old_partial_remainder <= output(61 downto 30);

	remainder_handler : div_remainder_handler
	port map(
	remainder => output(63 downto 32),
	numerator_sign => numerator(31),
	is_signed => is_signed,
	
	final_remainder => remainder
	);

	quotient_server : quotient_handler
	port map(
	quotient_in => output(31 downto 0),
	
	is_signed => is_signed,
	denominator_sign => denominator(31),
	numerator_sign => numerator(31),
	
	output => quotient
	);
 
	div_0_flag <= '1' when denominator = x"00000000" else '0';
	overflow_flag <= '1' when is_signed = '1' and denominator = x"FFFFFFFF" and numerator = x"80000000" else '0';

end Behavioral;

